/*
 * (C) Copyright 2006-2010 Nuxeo SAS (http://nuxeo.com/) and contributors.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser General Public License
 * (LGPL) version 2.1 which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl.html
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * Contributors:
 *     bstefanescu
 */
package org.nuxeo.gwt.habyt.upload.client.core;

import java.util.Iterator;
import java.util.LinkedList;

import org.nuxeo.gwt.habyt.upload.client.FileRef;
import org.nuxeo.gwt.habyt.upload.client.Uploader;

import com.google.gwt.user.client.Timer;

/**
 * A synchronous queue. No parallel uploads are allowed.
 * 
 * Note that all methods are invoked in the UI thread so no need for
 * synchronizing.
 * 
 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
 */
public class UploadQueue {

    protected LinkedList<Task> queue;

    protected Task currentTask;

    protected int timeout;

    protected Uploader uploader;

    /**
     * The current upload task
     */
    protected Task uploadTask;

    public UploadQueue(Uploader uploader) {
        this(uploader, Uploader.DEFAULT_TIMEOUT);
    }

    public UploadQueue(Uploader uploader, int timeout) {
        this.uploader = uploader;
        this.timeout = timeout;
        queue = new LinkedList<Task>();
    }

    /**
     * Start a new upload and its progress timer
     */
    protected void startNextTask() {
        if (currentTask != null) { // already one task running
            return;
        }
        if (queue.isEmpty()) {
            return;
        }
        currentTask = queue.removeFirst();
        currentTask.start();
    }

    protected void stopCurrentTask() {
        if (currentTask != null) {
            currentTask.dispose();
            currentTask = null;
        }
        startNextTask();
    }

    public boolean hasFileWithName(String name) {
        if (currentTask != null
                && name.equals(currentTask.getFileRef().getName())) {
            return true;
        }
        for (Task task : queue) {
            if (name.equals(task.getFileRef().getName())) {
                return true;
            }
        }
        return false;
    }

    public void add(UploadForm form) {
        Task task = new Task(form);
        queue.add(task);
        startNextTask();
    }

    public boolean remove(FileRef ref) {
        if (currentTask != null && ref.equals(currentTask.getFileRef())) {
            stopCurrentTask();
            return true;
        } else {
            // the file is queued - remove it
            Iterator<Task> it = queue.iterator();
            while (it.hasNext()) {
                Task task = it.next();
                if (ref.equals(task.getFileRef())) {
                    it.remove();
                    return true;
                }
            }
        }
        return false;
    }

    public boolean isEmpty() {
        return queue.isEmpty() && currentTask == null;
    }

    class Task {
        protected UploadForm form;

        protected Timer timer;

        public Task(UploadForm form) {
            this.form = form;
        }

        public void start() {
            if (timer == null) {
                form.submit();
                timer = new Timer() {
                    @Override
                    public void run() {
                        // System.out.println("timer check:" + getFileRef());
                        uploader.checkProgress(form.getFileRef());
                    }
                };
                timer.scheduleRepeating(timeout);
                // System.out.println("timer started:" + getFileRef());
            }
        }

        public void dispose() {
            if (timer != null) {
                timer.cancel();
                timer = null;
                form.destroy();
                // System.out.println("timer disposed:" + getFileRef());
            }
        }

        public boolean isRunning() {
            return timer != null;
        }

        public FileRef getFileRef() {
            return form.getFileRef();
        }
    }
}
